﻿using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Driver;
using Shipeng.Util;
using SqlSugar;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;
using Yitter.IdGenerator;
using YNTK.Common.Const;
using YNTK.Common.Enum;
using YNTK.Common.Filter;
using YNTK.Data.MongoDB.Repositorie;
using YNTK.Dependency;
using YNTK.DynamicApiController;
using YNTK.FriendlyException;
using YNTK.LinqBuilder;
using YNTK.Mapster;
using YNTK.Message.Interfaces.Message;
using YNTK.SimpleWorkflow.Entitys;
using YNTK.SimpleWorkflow.Interface;
using YNTK.System.Entitys.Dto.Common;
using YNTK.System.Entitys.Permission;
using YNTK.System.Entitys.Role;
using YNTK.System.Interfaces.Common;
using YNTK.System.Interfaces.Permission;
using YNTK.System.Interfaces.Resources;

namespace YNTK.SimpleWorkflow
{
    /// <summary>
    /// 通用简易工作流服务的实现
    /// 版 本：V1.0.0.0
    /// 版 权：云南通科科技有限公司（https://www.yntkkj.com）
    /// 作 者：李仕鹏
    /// 日 期：2022.10.11 
    /// </summary>
    [ApiDescriptionSettings(Tag = "通用简易工作流服务", Name = "SimpleWorkflow", Order = 790)]
    [Route("api/[controller]")]
    public class SimpleWorkflowService : ISimpleWorkflowService, IDynamicApiController, ITransient
    {
        private readonly ISqlSugarRepository<SimpleWorkflowConfigurationEntity> _workFlowConfigRepository;//通用简易工作流配置仓储
        private readonly IMongoDBRepository<SimpleWorkflowConfigurationEntity> _workFlowConfigMongoDbRepository;//通用简易工作流配置mongodb仓储

        private readonly ITkUsersService _tkUsersService;//用户服务
        private readonly IOrganizeService _organizeService;//组织服务
        private readonly IMechanismService _mechanismService;//机构服务
        private readonly IDictionaryService _dictionaryService;//字典服务
        private readonly IFileService _fileService;//文件服务
        private readonly ITkRoleService _tkRoleService;//角色服务
        private readonly IBusinessScopeService _businessScopeService;//管理体系认证业务范围服务
        private readonly IMessageService _messageService;//系统消息服务
        private readonly HttpContext _httpContext;
        private readonly string _workflowConfigs = "base_simpleworkflowconfiguration";//mongodb中通用简易工作流配置数据集名称

        private readonly ISqlSugarRepository<SimpleWorkflowEntity> _recordsRepository;//日常工作仓储
        private readonly IMongoDBRepository<SimpleWorkflowEntity> _recordsMongoDbRepository;//日常工作mongoddb仓储
        private readonly ISqlSugarRepository<SimpleWorkflowFilesEntity> _filesRepository;//日常工作相关附件仓储
        private readonly IMongoDBRepository<SimpleWorkflowFilesEntity> _filesMongoDbRepository;//日常工作相关附件mongoddb仓储
        private readonly ISqlSugarRepository<SimpleWorkflowDynamicFieldsEntity> _dynamicfieldsRepository;//日常工作动态字段仓储
        private readonly IMongoDBRepository<SimpleWorkflowDynamicFieldsEntity> _dynamicfieldsMongoDbRepository;//日常工作动态字段mongoddb仓储
        private readonly ISqlSugarRepository<SimpleWorkflowAssociatedConfigEntity> _configurationRepository;//日常工作关联流程节点配置仓储
        private readonly IMongoDBRepository<SimpleWorkflowAssociatedConfigEntity> _configurationMongoDbRepository;//日常工作关联流程节点配置mongoddb仓储
        private readonly ISqlSugarRepository<SimpleWorkflowAuditRecordsEntity> _auditRecordsRepository;//日常工作审核记录仓储
        private readonly IMongoDBRepository<SimpleWorkflowAuditRecordsEntity> _auditRecordsMongoDbRepository;//日常工作审核记录mongoddb仓储
        private readonly ISqlSugarRepository<SimpleWorkflowAuditRecordFilesEntity> _auditRecordFileRepository;//日常工作审核记录相关附件仓储
        private readonly IMongoDBRepository<SimpleWorkflowAuditRecordFilesEntity> _auditRecordFileMongoDbRepository;//日常工作审核记录相关附件mongoddb仓储
        private readonly string _records = "workflow_records";//mongodb中日常工作记录数据集名称
        private readonly string _files = "workflow_files";//mongodb中日常工作记录相关附件数据集名称
        private readonly string _dynamicfields = "workflow_dynamicfields";//mongodb中日常工作记录相关动态字段数据集名称
        private readonly string _configuration = "workflow_configuration";//mongodb中日常工作记录关联流程节点配置数据集名称
        private readonly string _auditRecords = "workflow_auditrecords";//mongodb中日常工作审核记录数据集名称
        private readonly string _auditRecordFiles = "workflow_auditrecordfiles";//mongodb中日常工作审核记录相关附件数据集名称

        private readonly ISqlSugarRepository<ProcessDocumentsFilesEntity> _processFileRepository;//流程文件仓储
        private readonly IMongoDBRepository<ProcessDocumentsFilesEntity> _processFileMongoDbRepository;//流程文件mongodb仓储
        private readonly string _processFiles = "base_processdocumentsfiles";//mongodb中流程文件数据集合名称

        /// <summary>
        /// 构造方法依赖注入
        /// </summary>
        /// <param name="workFlowConfigRepository">通用简易工作流配置仓储</param>
        /// <param name="workFlowConfigMongoDbRepository">通用简易工作流配置mongodb仓储</param>
        /// <param name="tkUsersService">用户服务</param>
        /// <param name="organizeService">组织服务</param>
        /// <param name="mechanismService">机构服务</param>
        /// <param name="dictionaryService">字典服务</param>
        /// <param name="fileService">文件服务</param>
        /// <param name="tkRoleService">角色服务</param>
        /// <param name="businessScopeService">管理体系认证业务范围服务</param>
        /// <param name="messageService">系统消息服务</param>
        /// <param name="recordsRepository">日常工作仓储</param>
        /// <param name="recordsMongoDbRepository">日常工作mongoddb仓储</param>
        /// <param name="filesRepository">日常工作相关附件仓储</param>
        /// <param name="filesMongoDbRepository">日常工作相关附件mongoddb仓储</param>
        /// <param name="dynamicfieldsRepository">日常工作动态字段仓储</param>
        /// <param name="dynamicfieldsMongoDbRepository">日常工作动态字段mongoddb仓储</param>
        /// <param name="configurationRepository">日常工作关联流程节点配置仓储</param>
        /// <param name="configurationMongoDbRepository">日常工作关联流程节点配置mongoddb仓储</param>
        /// <param name="auditRecordsRepository">日常工作审核记录仓储</param>
        /// <param name="auditRecordsMongoDbRepository">日常工作审核记录mongoddb仓储</param>
        /// <param name="auditRecordFileRepository">日常工作审核记录相关附件仓储</param>
        /// <param name="auditRecordFileMongoDbRepository">日常工作审核记录相关附件mongoddb仓储</param>
        /// <param name="processFileRepository">流程文件仓储</param>
        /// <param name="processFileMongoDbRepository">流程文件mongodb仓储</param>
        public SimpleWorkflowService(ISqlSugarRepository<SimpleWorkflowConfigurationEntity> workFlowConfigRepository,
            IMongoDBRepository<SimpleWorkflowConfigurationEntity> workFlowConfigMongoDbRepository,
            ITkUsersService tkUsersService, IOrganizeService organizeService,
            IMechanismService mechanismService, IDictionaryService dictionaryService,
            IFileService fileService, ITkRoleService tkRoleService,
            IBusinessScopeService businessScopeService, IMessageService messageService,
            ISqlSugarRepository<SimpleWorkflowEntity> recordsRepository,
            IMongoDBRepository<SimpleWorkflowEntity> recordsMongoDbRepository,
            ISqlSugarRepository<SimpleWorkflowFilesEntity> filesRepository,
            IMongoDBRepository<SimpleWorkflowFilesEntity> filesMongoDbRepository,
            ISqlSugarRepository<SimpleWorkflowDynamicFieldsEntity> dynamicfieldsRepository,
            IMongoDBRepository<SimpleWorkflowDynamicFieldsEntity> dynamicfieldsMongoDbRepository,
            ISqlSugarRepository<SimpleWorkflowAssociatedConfigEntity> configurationRepository,
            IMongoDBRepository<SimpleWorkflowAssociatedConfigEntity> configurationMongoDbRepository,
            ISqlSugarRepository<SimpleWorkflowAuditRecordsEntity> auditRecordsRepository,
            IMongoDBRepository<SimpleWorkflowAuditRecordsEntity> auditRecordsMongoDbRepository,
            ISqlSugarRepository<SimpleWorkflowAuditRecordFilesEntity> auditRecordFileRepository,
            IMongoDBRepository<SimpleWorkflowAuditRecordFilesEntity> auditRecordFileMongoDbRepository,
            ISqlSugarRepository<ProcessDocumentsFilesEntity> processFileRepository,
            IMongoDBRepository<ProcessDocumentsFilesEntity> processFileMongoDbRepository)
        {
            _workFlowConfigRepository = workFlowConfigRepository;
            _workFlowConfigMongoDbRepository = workFlowConfigMongoDbRepository;
            _tkUsersService = tkUsersService;
            _organizeService = organizeService;
            _mechanismService = mechanismService;
            _dictionaryService = dictionaryService;
            _fileService = fileService;
            _tkRoleService = tkRoleService;
            _businessScopeService = businessScopeService;
            _messageService = messageService;
            _httpContext = App.HttpContext;

            _recordsRepository = recordsRepository;
            _recordsMongoDbRepository = recordsMongoDbRepository;
            _filesRepository = filesRepository;
            _filesMongoDbRepository = filesMongoDbRepository;
            _dynamicfieldsRepository = dynamicfieldsRepository;
            _dynamicfieldsMongoDbRepository = dynamicfieldsMongoDbRepository;
            _configurationRepository = configurationRepository;
            _configurationMongoDbRepository = configurationMongoDbRepository;
            _auditRecordsRepository = auditRecordsRepository;
            _auditRecordsMongoDbRepository = auditRecordsMongoDbRepository;
            _auditRecordFileRepository = auditRecordFileRepository;
            _auditRecordFileMongoDbRepository = auditRecordFileMongoDbRepository;

            _processFileRepository = processFileRepository;
            _processFileMongoDbRepository = processFileMongoDbRepository;
        }

        #region 流程配置
        /// <summary>
        /// 获取通用表单类型
        /// </summary>
        /// <returns></returns>
        [HttpGet("generalfroms")]
        public TkResult<List<EnumListDto>> GetGeneralFromList()
        {
            Dictionary<int, string> dic = EnumHelper.EnumToDic<GeneralEnum>();
            var result = new List<EnumListDto>();
            foreach (KeyValuePair<int, string> kv in dic)
            {
                result.Add(new EnumListDto { Id = kv.Key.ToStr(), Value = kv.Key, Description = kv.Value });
            }
            return TkResult<List<EnumListDto>>.Success(result);
        }

        /// <summary>
        /// 根据工作流分类id获取流程节点配置数据
        /// </summary>
        /// <param name="classifyId">工作流分类id</param>
        /// <returns></returns>
        [HttpGet("gets/workflow/configs/{classifyId}")]
        public async Task<TkResult<List<SimpleWorkflowConfigurationListDto>>> GetConfigList([Required] string classifyId)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);

                string queryClassifyId = await _dictionaryService.GetIdAsync(classifyId, organizeId);
                Expression<Func<SimpleWorkflowConfigurationEntity, bool>> where = m =>
                m.OrganizeId == organizeId && m.ClassifyId == queryClassifyId && m.DeleteMark == null;

                //先从mongodb中获取
                var data = await _workFlowConfigMongoDbRepository.GetListAsync(_workflowConfigs, where);
                if (!data.Any())
                {
                    //从sqlserver中获取
                    data = await _workFlowConfigRepository.Entities.Where(where).ToListAsync();
                }
                var result = data.Adapt<List<SimpleWorkflowConfigurationListDto>>();
                if (result.Any())
                {
                    #region 处理流程节点返回数据
                    var orgIds = result.Select(r => r.organizeId).Distinct().ToList();
                    var orgs = await _organizeService.GetOrganizeListByIds(orgIds);
                    var mechanismIds = result.Where(r => !string.IsNullOrWhiteSpace(r.mechanismId))
                        ?.Select(r => r.mechanismId.Split(',').ToList())
                        ?.SelectMany(r => r).Distinct().ToList();
                    var mechanisms = !mechanismIds.Any() ? new List<MechanismEntity>() :
                        await _mechanismService.GetMechanismListAsync(null, mechanismIds);
                    var roleIds = result.Where(r => !string.IsNullOrWhiteSpace(r.roleId))
                        ?.Select(r => r.roleId).Distinct().ToList();
                    var roles = !roleIds.Any() ? new List<TkRoleEntity>() :
                        await _tkRoleService.GetTkRoleListByIdsAsync(roleIds);
                    var classifyIds = result.Select(r => r.classifyId.Split(',').ToList())
                        ?.SelectMany(r=>r).Distinct().ToList();
                    var classifys = await _dictionaryService.GetDictionaryListByIds(classifyIds);
                    var userIds = result.Where(r => !string.IsNullOrWhiteSpace(r.userIds))
                        ?.Select(r => r.userIds.Split(',').ToList())?.ToList()
                        ?.SelectMany(r => r).Distinct().ToList();
                    var users = await _tkUsersService.GetUserListByIds(userIds);
                    result.ForEach(config =>
                    {
                        if (!string.IsNullOrWhiteSpace(config.organizeId))
                            config.organizeName = orgs?.FirstOrDefault(r => r.Id == config.organizeId)?.FullName;
                        if (!string.IsNullOrWhiteSpace(config.mechanismId))
                        {
                            config.mechanismName = string.Join('/', mechanisms
                                ?.Where(r=> config.mechanismId.Split(',').ToList().Contains(r.Id))
                                ?.Select(r=>r.Name).ToList());
                            config.mechanismName = mechanisms?.FirstOrDefault(r => r.Id == config.mechanismId)?.Name;
                        }
                        if (!string.IsNullOrWhiteSpace(config.roleId))
                            config.roleName = roles?.FirstOrDefault(r => r.Id == config.roleId)?.Name;
                        if (!string.IsNullOrWhiteSpace(config.classifyId))
                        {
                            var classData=classifys?.Where(r => config.classifyId.Split(',').ToList().Contains(r.Id))
                                ?.Select(r => r.Name).ToList();
                            if(classData.Any()) config.classifyName =string.Join('/', classData);
                        }
                        if (!string.IsNullOrWhiteSpace(config.userIds))
                            config.userNames = string.Join(",", users?.Where(r => config.userIds.Split(',').ToList().Contains(r.Id))
                            ?.Select(r => r.RealName)?.ToList());
                    });
                    #endregion
                }
                return TkResult<List<SimpleWorkflowConfigurationListDto>>.Success(result);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"根据工作流分类id获取流程节点配置数据发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 添加工作流流程节点
        /// </summary>
        /// <param name="input">添加工作流流程节点请求模型</param>
        /// <returns></returns>
        [HttpPost("add/workflow/config/node")]
        public async Task AddConfig([FromBody] AddSimpleWorkflowConfigurationRequestModel input)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);

                if ((await GetConfigAsync(r => r.OrganizeId == organizeId && r.ClassifyId == input.classifyId &&
                r.NodeName == input.nodeName && r.DeleteMark == null)) != null)
                    throw YNTKException.Oh(ErrorCode.Workflow0001);

                var entity = input.Adapt<SimpleWorkflowConfigurationEntity>();
                if(input.type==1) entity.GeneralFormId = entity.ClassifyId.ToInt();
                entity.OrganizeId = organizeId;
                entity.SubsidiaryMechanismId = mechanismId;
                //if (input.userIds.Any()) entity.UserIds = string.Join(',', input.userIds);
                if (input.userIds != null && input.userIds.Length > 0) entity.UserIds = string.Join(',', input.userIds);
                else entity.UserIds = "";
                //获取当前流程最后一个节点排序
                entity.SortCode = (await _workFlowConfigRepository.Entities.Where(r =>
                r.OrganizeId == organizeId && r.ClassifyId == entity.ClassifyId &&
                r.DeleteMark == null).MaxAsync(r => r.SortCode) ?? 0) + 1;

                #region 添加流程节点信息
                var isOk = await _workFlowConfigRepository.Context.Insertable(entity)
                    .CallEntityMethod(m => m.Creator()).ExecuteReturnEntityAsync();
                _ = isOk ?? throw YNTKException.Oh(ErrorCode.Workflow0002);

                //保存流程节点到mongodb
                entity = isOk;
                var result = await _workFlowConfigMongoDbRepository.AddAsync(entity, _workflowConfigs);
                if (!result) throw YNTKException.Oh(ErrorCode.Workflow0003);
                #endregion
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"添加工作流流程节点发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 修改工作流流程节点信息
        /// </summary>
        /// <param name="input">修改工作流流程节点请求模型</param>
        /// <returns></returns>
        [HttpPost("update/workflow/config/node")]
        public async Task UpdateConfig([FromBody] UpdateSimpleWorkflowConfigurationRequestModel input)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);
                var entity = await GetConfigAsync(r => r.Id == input.id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Workflow0004);
                if (entity.OrganizeId != organizeId) throw YNTKException.Oh(ErrorCode.D1016);
                if(entity.Type==1 && entity.GeneralFormId!=input.classifyId.ToInt())
                    throw YNTKException.Oh("通用表单唯一标识错误");

                if ((await GetConfigAsync(r => r.OrganizeId == organizeId && r.ClassifyId == input.classifyId &&
                r.NodeName == input.nodeName && r.Id != input.id && r.DeleteMark == null)) != null)
                    throw YNTKException.Oh(ErrorCode.Workflow0001);

                //entity = input.Adapt<SimpleWorkflowConfigurationEntity>();
                entity = input.Mapper(entity);
                //if (input.userIds.Any()) entity.UserIds = string.Join(',', input.userIds);
                if (input.userIds != null && input.userIds.Length > 0) entity.UserIds = string.Join(',', input.userIds);
                else entity.UserIds = "";

                #region 保存流程节点
                var isOK = await _workFlowConfigRepository.Context.Updateable(entity)
                .IgnoreColumns(ignoreAllNullColumns: true)
                .CallEntityMethod(m => m.LastModify()).ExecuteCommandAsync();
                if (!(isOK > 0))
                    throw YNTKException.Oh(ErrorCode.Workflow0005);

                //保存流程节点到mongodb
                entity.LastModifyUserId = userId;
                entity.LastModifyTime = DateTime.Now;
                var update = await _workFlowConfigMongoDbRepository.UpdateAsync(entity, _workflowConfigs, m => m.Id == entity.Id);
                if (!(update.ModifiedCount > 0)) throw YNTKException.Oh(ErrorCode.Workflow0003);
                #endregion
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"修改工作流流程节点信息发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除工作流流程节点
        /// </summary>
        /// <param name="id">流程节点id</param>
        /// <returns></returns>
        [HttpDelete("delete/workflow/config/node/{id}")]
        public async Task DeleteConfig([Required] string id)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);
                var entity = await GetConfigAsync(r => r.Id == id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Workflow0004);
                if (entity.OrganizeId != organizeId) throw YNTKException.Oh(ErrorCode.D1016);

                #region 删除流程节点
                var isOk = await _workFlowConfigRepository.Context.Deleteable(entity).ExecuteCommandAsync();
                if (!(isOk > 0))
                    throw YNTKException.Oh(ErrorCode.Workflow0006);

                //从mongodb上删除
                var delete = await _workFlowConfigMongoDbRepository.DeleteAsync(_workflowConfigs, m => m.Id == id);
                if (!(delete > 0)) throw YNTKException.Oh(ErrorCode.Workflow0007);
                #endregion
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"删除工作流流程节点发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 更新工作流流程节点状态(启用/禁用)
        /// </summary>
        /// <param name="id">流程节点id</param>
        /// <returns></returns>
        [HttpPut("state/workflow/config/node/{id}")]
        public async Task UpdateConfigState([Required] string id)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);
                var entity = await GetConfigAsync(r => r.Id == id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Workflow0004);
                if (entity.OrganizeId != organizeId) throw YNTKException.Oh(ErrorCode.D1016);

                #region 更新流程节点状态
                var isOk = await _workFlowConfigRepository.Context.Updateable<SimpleWorkflowConfigurationEntity>()
                .SetColumns(it => new SimpleWorkflowConfigurationEntity()
                {
                    EnabledMark = SqlFunc.IIF(it.EnabledMark == 1, 0, 1),
                    LastModifyUserId = userId,
                    LastModifyTime = SqlFunc.GetDate()
                }).Where(it => it.Id == id).ExecuteCommandAsync();
                if (!(isOk > 0))
                    throw YNTKException.Oh(ErrorCode.Workflow0008);

                //mongodb更新流程节点状态
                var mongoEntity = entity.Adapt<SimpleWorkflowConfigurationEntity>();
                mongoEntity.EnabledMark = entity.EnabledMark == 1 ? 0 : 1;
                mongoEntity.LastModifyUserId = userId;
                mongoEntity.LastModifyTime = DateTime.Now;
                var update = await _workFlowConfigMongoDbRepository.UpdateAsync(mongoEntity, _workflowConfigs, m => m.Id == mongoEntity.Id);
                if (!(update.ModifiedCount > 0)) throw YNTKException.Oh(ErrorCode.Workflow0009);
                #endregion
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"更新工作流流程节点状态(启用/禁用)发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 排序工作流流程节点
        /// </summary>
        /// <param name="sort">通用排序请求模型</param>
        /// <returns></returns>
        [HttpPut("sort/workflow/config/node")]
        public async Task SortConfig(SortRequetModel sort)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);
                var entity = await GetConfigAsync(r => r.Id == sort.id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Workflow0004);
                if (entity.OrganizeId != organizeId) throw YNTKException.Oh(ErrorCode.D1016);

                #region 更新流程节点排序
                long? currentSort = entity.SortCode;
                //获取当前流程所有节点数据
                var nodeList = await GetNodeConfigListAsync(r =>r.OrganizeId== organizeId && r.ClassifyId == entity.ClassifyId && r.DeleteMark == null);
                if (!nodeList.Any()) throw YNTKException.Oh(ErrorCode.Workflow0010);
                if (nodeList.Count == 1) throw YNTKException.Oh(ErrorCode.Workflow0011);
                nodeList = nodeList.OrderBy(r => r.SortCode).ToList();
                var sortData = new List<SimpleWorkflowConfigurationEntity>();
                long? sortIndex = 0;
                switch (sort.SortType)
                {
                    case SortTypeEnum.Ascending://升序
                        #region 升序  
                        //获取当前节点的前一个节点
                        var beforeNode = nodeList.FirstOrDefault(r => r.SortCode < currentSort);
                        if (beforeNode == null) throw YNTKException.Oh(ErrorCode.Workflow0012);
                        //当前节点排序改为上一个节点排序
                        entity.SortCode = beforeNode.SortCode;
                        entity.LastModifyUserId = userId;
                        entity.LastModifyTime = DateTime.Now;
                        sortData.Add(entity);
                        //上一个节点排序改为当前节点排序
                        beforeNode.SortCode = currentSort;
                        beforeNode.LastModifyUserId = userId;
                        beforeNode.LastModifyTime = DateTime.Now;
                        sortData.Add(beforeNode);
                        #endregion
                        break;
                    case SortTypeEnum.Descending://降序
                        #region 降序
                        //获取当前节点的下一个节点
                        var afterNode = nodeList.FirstOrDefault(r => r.SortCode > currentSort);
                        if (afterNode == null) throw YNTKException.Oh(ErrorCode.Workflow0013);
                        //当前节点排序改为下一个节点排序
                        entity.SortCode = afterNode.SortCode;
                        entity.LastModifyUserId = userId;
                        entity.LastModifyTime = DateTime.Now;
                        sortData.Add(entity);
                        //下一个节点排序改为当前节点排序
                        afterNode.SortCode = currentSort;
                        afterNode.LastModifyUserId = userId;
                        afterNode.LastModifyTime = DateTime.Now;
                        sortData.Add(afterNode);
                        #endregion
                        break;
                    case SortTypeEnum.Stick://置顶
                        #region 置顶
                        //获取当前节点前面的的节点数据
                        var beforeList = nodeList.Where(r => r.SortCode < currentSort)?.ToList();
                        if (!beforeList.Any()) throw YNTKException.Oh(ErrorCode.Workflow0012);
                        long? minSort = beforeList.Min(r => r.SortCode);//置顶排序
                        entity.SortCode = minSort;//当前节点改为置顶节点
                        entity.LastModifyUserId = userId;
                        entity.LastModifyTime = DateTime.Now;
                        sortData.Add(entity);
                        beforeList.ForEach(before =>
                        {
                            sortIndex = before.SortCode+1;//排在当前节点之前的都+1
                            before.SortCode = sortIndex >= currentSort ? currentSort : sortIndex;
                            before.LastModifyUserId = userId;
                            before.LastModifyTime = DateTime.Now;
                            sortData.Add(before);
                        });
                        #endregion
                        break;
                    case SortTypeEnum.Doubt://置尾
                        #region 置尾
                        //获取排在当前节点之后的节点数据
                        var afterList = nodeList.Where(r => r.SortCode > currentSort)?.ToList();
                        if (!afterList.Any()) throw YNTKException.Oh(ErrorCode.Workflow0013);
                        long? maxSort = afterList.Max(r => r.SortCode);//排在最后面
                        entity.SortCode = maxSort;//当前节点改为最末节点
                        entity.LastModifyUserId = userId;
                        entity.LastModifyTime = DateTime.Now;
                        sortData.Add(entity);
                        afterList.ForEach(after =>
                        {
                            sortIndex = after.SortCode-1;//排在当前节点之前的都-1
                            after.SortCode = sortIndex <= currentSort ? currentSort : sortIndex;
                            after.LastModifyUserId = userId;
                            after.LastModifyTime = DateTime.Now;
                            sortData.Add(after);
                        });
                        #endregion
                        break;
                    default:
                        throw YNTKException.Oh(ErrorCode.Workflow0010);
                }
                var update = await _workFlowConfigRepository.UpdateAsync(sortData);
                if (!(update > 0)) throw YNTKException.Oh(ErrorCode.Workflow0010);
                update = await _workFlowConfigMongoDbRepository.UpdateManayAsync(sortData, _workflowConfigs);
                if (!(update > 0)) throw YNTKException.Oh(ErrorCode.Workflow0014);
                #endregion
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"工作流流程节点{sort.SortType.GetDescription()}发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 根据条件获取流程配置信息
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        private async Task<SimpleWorkflowConfigurationEntity> GetConfigAsync
            (Expression<Func<SimpleWorkflowConfigurationEntity, bool>> where)
        {
            //从从mongodb中获取
            var entity = await _workFlowConfigMongoDbRepository.GetAsync(_workflowConfigs, where);
            //再从sqlserver中获取
            if (entity == null) entity = await _workFlowConfigRepository.FirstOrDefaultAsync(where);
            return entity;
        }

        /// <summary>
        /// 根据条件获取工作流流程节点配置数据
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        private async Task<List<SimpleWorkflowConfigurationEntity>> GetNodeConfigListAsync
            (Expression<Func<SimpleWorkflowConfigurationEntity, bool>> where)
        {
            //从从mongodb中获取
            var result = await _workFlowConfigMongoDbRepository.GetListAsync(_workflowConfigs, where);
            //再从sqlserver中获取
            if (!result.Any()) result = await _workFlowConfigRepository.Entities.Where(where).ToListAsync();
            return result;
        }

        #endregion

        #region 流程文件
        /// <summary>
        /// 根据工作流分类获取流程文件数据
        /// </summary>
        /// <param name="classifyId">工作流分类id</param>
        /// <returns></returns>
        [HttpGet("process/documents/file/gets/{classifyId}")]
        public async Task<TkResult<List<ProcessDocumentsFilesListDto>>> GetProcessFiles([Required] string classifyId)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);

                string queryClassifyId = await _dictionaryService.GetIdAsync(classifyId, organizeId);
                Expression<Func<ProcessDocumentsFilesEntity, bool>> where = m =>
                m.OrganizeId == organizeId && m.ClassifyId == queryClassifyId;

                //先从mongodb中获取
                var data = await _processFileMongoDbRepository.GetListAsync(_processFiles, where);
                if (!data.Any())
                {
                    //从sqlserver中获取
                    data = await _processFileRepository.Entities.Where(where).ToListAsync();
                }
                var result = data.Adapt<List<ProcessDocumentsFilesListDto>>();
                return TkResult<List<ProcessDocumentsFilesListDto>>.Success(result);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"根据工作流分类获取流程文件数据发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 添加流程文件
        /// </summary>
        /// <param name="file">添加流程文件请求模型</param>
        /// <returns></returns>
        [HttpPost("process/documents/file/add")]
        public async Task AddProcessFile(AddProcessDocumentsFileRequestModel file)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);

                var entity = file.Adapt<ProcessDocumentsFilesEntity>();
                entity.Id= YitIdHelper.NextId().ToString();
                entity.OrganizeId = organizeId;
                entity.MechanismId = mechanismId;

                //sqlserver添加流程文件信息
                var isOk = await _processFileRepository.Context.Insertable(entity).ExecuteReturnEntityAsync();
                _ = isOk ?? throw YNTKException.Oh(ErrorCode.Workflow0044);

                //mongodb添加流程文件信息
                entity = isOk;
                var result = await _processFileMongoDbRepository.AddAsync(entity, _processFiles);
                if (!result) throw YNTKException.Oh(ErrorCode.Workflow0045);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"添加流程文件发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除流程文件
        /// </summary>
        /// <param name="id">流程文件记录id</param>
        /// <returns></returns>
        [HttpDelete("process/documents/file/delete/{id}")]
        public async Task DeleteProcessFile([Required] string id)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);

                var entity = await _processFileMongoDbRepository.GetAsync(_processFiles,m=>m.Id==id);
                if (entity == null) entity = await _processFileRepository.FirstOrDefaultAsync(r=>r.Id==id);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Workflow0046);

                var isOk = await _processFileRepository.Context.Deleteable(entity).ExecuteCommandAsync();
                if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.Workflow0047);

                var delete = await _processFileMongoDbRepository.DeleteAsync(_processFiles,m=>m.Id==id);
                if (!(delete > 0)) throw YNTKException.Oh(ErrorCode.Workflow0048);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"删除流程文件发生异常：{ex.Message}");
            }
        }
        #endregion


        #region 日常工作
        /// <summary>
        /// 获取状态类型
        /// </summary>
        /// <returns></returns>
        [HttpGet("auditstate")]
        public TkResult<List<EnumListDto>> GetAuditStateTypeList()
        {
            Dictionary<int, string> dic = EnumHelper.EnumToDic<AuditStateEnum>();
            var result = new List<EnumListDto>();
            foreach (KeyValuePair<int, string> kv in dic)
            {
                result.Add(new EnumListDto { Id = kv.Key.ToStr(), Value = kv.Key, Description = kv.Value });
            }
            return TkResult<List<EnumListDto>>.Success(result);
        }

        /// <summary>
        /// 获取动态字段类型
        /// </summary>
        /// <returns></returns>
        [HttpGet("dynamicfieldtype")]
        public TkResult<List<EnumListDto>> GetDynamicFieldTypeList()
        {
            Dictionary<int, string> dic = EnumHelper.EnumToDic<DynamicFieldTypeEnum>();
            var result = new List<EnumListDto>();
            foreach (KeyValuePair<int, string> kv in dic)
            {
                result.Add(new EnumListDto { Id = kv.Key.ToStr(), Value = kv.Key, Description = kv.Value });
            }
            return TkResult<List<EnumListDto>>.Success(result);
        }

        /// <summary>
        /// 分页获取日常工作记录数据
        /// </summary>
        /// <param name="query">查询日常工作记录数据请求模型</param>
        /// <returns></returns>
        [HttpPost("workflow/gets")]
        public async Task<TkPageResult<DailyWorkListDto>> Gets([FromBody] QueryDailyWorkFilterRequestModel query)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                string roleId = user.Subject.FindFirst(ClaimConst.ROLEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;

                #region 获取日常工作记录数据
                var pageList = new SqlSugarPagedList<DailyWorkListDto>();
                #region 组装查询条件
                Expression<Func<SimpleWorkflowEntity, bool>> where = m =>
               m.DeleteMark == null && (m.CreatorUserId == userId ||
               (m.SharedScope == 0 && m.OrganizeId == organizeId && m.EnabledMark == 1) ||
               (m.SharedScope == 1 && m.MechanismId == mechanismId && m.EnabledMark == 1) ||
               (m.SharedScope == 2 && m.SharedScopeValue.Contains(roleId) && m.EnabledMark == 1) ||
               (m.SharedScope == 3 && m.SharedScopeValue.Contains(userId) && m.EnabledMark == 1) || 
               m.DisposeUserIds.Contains(userId) || m.NextDisposenUserId==userId);

                if (query.enabledMark == 1) where = where.And(m => m.EnabledMark == 1);
                if (query.enabledMark == 0) where = where.And(m => m.EnabledMark != 1);
                if (!string.IsNullOrWhiteSpace(query.organizeId))
                    where = where.And(m => m.OrganizeId == query.organizeId);
                if (!string.IsNullOrWhiteSpace(query.mechanismId))
                {
                    string queryMechanismId = await _mechanismService.GetIdAsync(query.mechanismId, organizeId);
                    where = where.And(m => m.MechanismId == queryMechanismId);
                }
                if (!string.IsNullOrWhiteSpace(query.classifyId))
                {
                    string queryClassifyId = await _dictionaryService.GetIdAsync(query.classifyId, organizeId);
                    where = where.And(m => m.ClassifyId == queryClassifyId);
                }
                if (!string.IsNullOrWhiteSpace(query.businessScopeId))
                {
                    string queryBusinessScopeId = await _businessScopeService.GetIdAsync(query.businessScopeId);
                    where = where.And(m => m.BusinessScopeId == queryBusinessScopeId);
                }
                if (query.sharedScope != null)
                    where = where.And(m => m.SharedScope == query.sharedScope.GetHashCode());
                if(query.state!=null) where = where.And(m => m.State == query.state.GetHashCode());
                if (query.startTime != null) where = where.And(m => m.CreatorTime >= query.startTime);
                if (query.endTime != null) where = where.And(m => m.CreatorTime <= query.endTime);
                if (!string.IsNullOrWhiteSpace(query.keyword))
                    where = where.And(m => m.Title.Contains(query.keyword));
                #endregion

                #region 从mongodb中获取日常工作记录数据
                //排序生成器
                var builderSort = Builders<SimpleWorkflowEntity>.Sort;
                //排序约束   Ascending 正序    Descending 倒序
                var sort = builderSort.Ascending(r => r.SortCode).Descending(r => r.CreatorTime);
                //Item1.结果集 Item2.总条数 Item3.总页数
                (List<SimpleWorkflowEntity>, int, int) result =
                    await _recordsMongoDbRepository.GetListAsync(_records,
                    where, query.currentPage, query.pageSize, null, sort);
                pageList.list = result.Item1.Adapt<List<DailyWorkListDto>>();
                pageList.pagination = new PagedModel()
                {
                    PageIndex = query.currentPage,
                    PageSize = query.pageSize,
                    Total = result.Item2,
                    PageCount = result.Item3
                };
                #endregion
                if (pageList.list == null || pageList.list.Count() <= 0)
                {
                    #region 从sqlserver数据库中获取档案数据
                    var sqlResult = await _recordsRepository.Entities.Where(where)
                         .OrderBy(r => r.SortCode, OrderByType.Asc)
                         .OrderBy(r => r.CreatorTime, OrderByType.Desc)
                         .ToPagedListAsync(query.currentPage, query.pageSize);
                    pageList.list = sqlResult.list.Adapt<List<DailyWorkListDto>>();
                    pageList.pagination = sqlResult.pagination;
                    #endregion
                }
                #endregion

                #region 处理日常工作返回数据
                if (pageList.list.Any())
                {
                    var orgIds = pageList.list.Select(r => r.organizeId).Distinct().ToList();
                    var orgs = await _organizeService.GetOrganizeListByIds(orgIds);
                    var mechanismIds = pageList.list.Where(r => !string.IsNullOrWhiteSpace(r.mechanismId))
                        ?.Select(r => r.mechanismId.Split(',').ToList())
                        ?.SelectMany(r => r).Distinct().ToList();
                    var mechanisms = !mechanismIds.Any() ? new List<MechanismEntity>() :
                        await _mechanismService.GetMechanismListAsync(null, mechanismIds);
                    var classifyIds = pageList.list.Select(r => r.classifyId.Split(',').ToList())
                       .SelectMany(r => r).Distinct().ToList();
                    var businessScopeIds = pageList.list.Where(r => !string.IsNullOrWhiteSpace(r.businessScopeId))
                        ?.ToList()?.Select(r => r.businessScopeId.Split(',').ToList())
                        .SelectMany(r => r).Distinct().ToList();
                    var businessScopes = await _businessScopeService.GetBusinessScopeListAsync(businessScopeIds);
                    var classifys = await _dictionaryService.GetDictionaryListByIds(classifyIds);
                    var userIds = pageList.list.Select(r => r.creatorUserId).Distinct().ToList().Union(
                         pageList.list.Where(r=>!string.IsNullOrWhiteSpace(r.nextDisposenUserId))
                         ?.Select(r => r.nextDisposenUserId)?.Distinct()?.ToList()).ToList();
                    var users = await _tkUsersService.GetUserListByIds(userIds);
                    var nodeIds = pageList.list.Where(r => !string.IsNullOrWhiteSpace(r.nextDisposenNodeId))
                         ?.Select(r => r.nextDisposenNodeId)?.Distinct()?.ToList();
                    var nodes = !nodeIds.Any() ? new List<SimpleWorkflowAssociatedConfigEntity>() : 
                        await GetWorkflowConfigListAsync(r=> nodeIds.Contains(r.Id));
                    pageList.list.ForEach(work =>
                    {
                        work.sharedScopeText = EnumHelper.GetEnumDescriptionString
                        (work.sharedScope, typeof(SharedScopeEnum));
                        work.stateText = EnumHelper.GetEnumDescriptionString
                        (work.state, typeof(AuditStateEnum));
                        if (!string.IsNullOrWhiteSpace(work.organizeId))
                            work.organizeName = orgs?.FirstOrDefault(r => r.Id == work.organizeId)?.FullName;
                        if (!string.IsNullOrWhiteSpace(work.mechanismId))
                            work.mechanismName = mechanisms?.FirstOrDefault(r => r.Id == work.mechanismId.Split(',').Last())?.Name;
                        if (!string.IsNullOrWhiteSpace(work.classifyId))
                            work.classifyName = classifys?.FirstOrDefault(r => r.Id == work.classifyId.Split(',').Last())?.Name;
                        if (!string.IsNullOrWhiteSpace(work.businessScopeId))
                            work.businessScopeName = businessScopes?.FirstOrDefault(r => r.Id == work.businessScopeId.Split(',').Last())?.Name;
                        if (!string.IsNullOrWhiteSpace(work.creatorUserId))
                            work.creatorUserName = users?.FirstOrDefault(r => r.Id == work.creatorUserId)?.RealName;
                        if (!string.IsNullOrWhiteSpace(work.nextDisposenUserId))
                            work.nextDisposenUserName = users?.FirstOrDefault(r => r.Id == work.nextDisposenUserId)?.RealName;
                        if (!string.IsNullOrWhiteSpace(work.nextDisposenNodeId))
                            work.nextDisposenNodeName = nodes?.FirstOrDefault(r => r.Id == work.nextDisposenNodeId)?.NodeName;
                    });
                }
                #endregion

                return TkPageResult<DailyWorkListDto>.Success(pageList);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"分页获取日常工作记录数据发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 获取日常工作记录详细信息
        /// </summary>
        /// <param name="id">日常工作id</param>
        /// <returns></returns>
        [HttpGet("get/{id}")]
        public async Task<TkResult<DailyWorkDto>> Get([Required] string id)
        {
            try
            {
                var entity = await _recordsMongoDbRepository.GetAsync(_records,m=>m.Id==id && m.DeleteMark==null);
                if (entity == null) entity = await _recordsRepository.FirstOrDefaultAsync(r=>r.Id==id && r.DeleteMark==null);
                if (entity == null) throw YNTKException.Oh(ErrorCode.Workflow0025);
                var work = entity.Adapt<DailyWorkDto>();

                #region 处理返回信息
                work.sharedScopeText = EnumHelper.GetEnumDescriptionString
                        (work.sharedScope, typeof(SharedScopeEnum));
                work.stateText = EnumHelper.GetEnumDescriptionString
                       (work.state, typeof(AuditStateEnum));
                if (!string.IsNullOrWhiteSpace(work.organizeId) && work.organizeId != "org00000000")
                    work.organizeName = (await _organizeService.GetOrganizeListByIds
                            (new List<string>() { work.organizeId }))?[0].FullName;
                if (!string.IsNullOrWhiteSpace(work.mechanismId) && work.mechanismId != "jg000000")
                    work.mechanismName = (await _mechanismService.GetMechanismInfoAsync(work.mechanismId.Split(',').Last()))?.Name;
                if (!string.IsNullOrWhiteSpace(work.classifyId))
                    work.classifyName = (await _dictionaryService.GetDictionaryInfoAsync(work.classifyId.Split(',').Last()))?.Name;
                if (!string.IsNullOrWhiteSpace(work.businessScopeId))
                    work.businessScopeName = (await _businessScopeService.GetBusinessScopeInfoAsync(work.businessScopeId.Split(',').Last()))?.Name;
                #region 处理共享范围
                if (!string.IsNullOrWhiteSpace(work.sharedScopeValue))
                {
                    //共享范围(0.全组织 1.特定机构 2.特定角色 3.特定用户 4.仅自己可见)
                    switch (work.sharedScope)
                    {
                        case 0:
                            work.sharedScopeValueText = "全组织";
                            break;
                        case 1:
                            var dic = await _mechanismService.GetIdsAsync(work.sharedScopeValue.Split(',').ToList(), work.organizeId);
                            var values = dic.Values.ToList();
                            work.sharedScopeValueText = string.Join(',',values.Select(r => r.Item2).ToList());
                            work.sharedScopeMechanismValue = values.Select(r => r.Item1.Split(',').ToArray())?.ToList();
                            break;
                        case 2:
                            work.sharedScopeValueText = string.Join(',', (await _tkRoleService
                                .GetTkRoleListByIdsAsync(work.sharedScopeValue.Split(',').ToList()))
                                ?.Select(r => r.Name)?.ToList());
                            break;
                        case 3:
                            work.sharedScopeValueText = string.Join(',', (await _tkUsersService
                               .GetUserListByIds(work.sharedScopeValue.Split(',').ToList()))
                               ?.Select(r => r.RealName)?.ToList());
                            break;
                        case 4:
                            work.sharedScopeValueText = "仅自己可见";
                            break;
                    }
                }
                #endregion
                if (!string.IsNullOrWhiteSpace(work.creatorUserId))
                    work.creatorUserName = (await _tkUsersService.GetUserInfoByUserId(work.creatorUserId))?.RealName;
                if (!string.IsNullOrWhiteSpace(work.nextDisposenUserId))
                    work.nextDisposenUserName = (await _tkUsersService.GetUserInfoByUserId(work.nextDisposenUserId))?.RealName;
                if (!string.IsNullOrWhiteSpace(work.nextDisposenNodeId))
                    work.nextDisposenNodeName =(await GetWorkflowConfigListAsync(r => r.Id == work.nextDisposenNodeId))?[0].NodeName;
                #endregion

                //获取日常工作相关附件数据
                var fileData = await GetWorkflowFileListAsync(id);
                work.fileData= fileData.Adapt<List<WorkflowFileListDto>>();
                //获取日常工作流程节点配置数据
                var dynamicData = await GetWorkflowDynamicFieldsListAsync(id);
                work.dynamicData = dynamicData.Adapt<List<WorkflowDynamicFieldsListDto>>();
                if (work.dynamicData.Any())
                {
                    work.dynamicData.ForEach(dynamic => {
                        dynamic.fieldTypeText = EnumHelper.GetEnumDescriptionString
                        (dynamic.fieldType, typeof(DynamicFieldTypeEnum));
                    });
                }

                #region 累加浏览次数
                entity.ViewCount++;
                await _recordsRepository.Context.Updateable(entity)
                    .IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
                await _recordsMongoDbRepository.UpdateAsync(entity, _records, m => m.Id == entity.Id);
                #endregion

                return TkResult<DailyWorkDto>.Success(work);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"获取日常工作记录详细信息发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 添加日常工作信息
        /// </summary>
        /// <param name="input">添加日常工作请求模型</param>
        /// <returns></returns>
        [HttpPost("workflow/add")]
        public async Task Add([FromBody] AddDailyWorkRequestModel input)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                string roleId = user.Subject.FindFirst(ClaimConst.ROLEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);

                //根据工作流分类id获取流程节点配置数据
                var nodeList = await GetNodeConfigListAsync(r => r.OrganizeId== organizeId && 
                r.ClassifyId == input.classifyId && r.EnabledMark == 1 && r.DeleteMark == null);             
                if (!nodeList.Any()) throw YNTKException.Oh(ErrorCode.Workflow0024);
                if ((await GetWorkflowEntityInfoAsync(r => r.OrganizeId == organizeId && r.ClassifyId == input.classifyId &&
                r.MechanismId == mechanismId && r.Title == input.title && r.DeleteMark == null)) != null)
                    throw YNTKException.Oh(ErrorCode.Workflow0015);

                var entity = input.Adapt<SimpleWorkflowEntity>();
                entity.SharedScope = input.sharedScope.GetHashCode();
                entity.OrganizeId = organizeId;
                entity.MechanismId = mechanismId;
                entity.Index = 0;//当前节点顺序
                //状态(0.未提交 1.待审核 2.审核不通过 3.已驳回 4.审核通过 5.待确认 6.已完成)
                entity.State = AuditStateEnum.Uncommitted.GetHashCode();//状态改为“未提交”

                #region 保存日常工作记录
                #region 保存日常工作到sqlserver
                var isOk = await _recordsRepository.Context.Insertable(entity)
                    .CallEntityMethod(m => m.Creator()).ExecuteReturnEntityAsync();
                _ = isOk ?? throw YNTKException.Oh(ErrorCode.Workflow0016);
                #endregion

                #region 保存日常工作到mongodb
                entity = isOk;
                var result = await _recordsMongoDbRepository.AddAsync(entity, _records);
                if (!result) throw YNTKException.Oh(ErrorCode.Workflow0017);
                #endregion

                //保存日常工作相关附件
                await SaveWorkflowFileAsync(entity, input.fileData);
                //保存日常工作动态字段
                await SaveWorkflowDynamicFieldsAsync(entity, input.dynamicData);
                //保存日常工作流程节点配置
                await SaveWorkflowConfigAsync(entity,nodeList);
                #endregion
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"添加日常工作信息发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 修改日常工作记录信息
        /// </summary>
        /// <param name="input">修改日常工作请求模型</param>
        /// <returns></returns>
        [HttpPut("workflow/update")]
        public async Task Update([FromBody] UpdateDailyWorkRequestModel input)
        {
            try
            {
                #region 权限验证
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                string roleId = user.Subject.FindFirst(ClaimConst.ROLEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);

                var entity = await GetWorkflowEntityInfoAsync(r => r.Id == input.id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Workflow0025);
                if(entity.CreatorUserId!= userId) throw YNTKException.Oh(ErrorCode.D1016);
                if(entity.State!= AuditStateEnum.Uncommitted.GetHashCode() && 
                    entity.State!=AuditStateEnum.NoPass.GetHashCode() &&
                    !(entity.State== AuditStateEnum.Rejected.GetHashCode() && entity.NextDisposenUserId==userId))
                    throw YNTKException.Oh(ErrorCode.Workflow0028);
                var records = await GetWorkflowEntityInfoAsync(r => r.OrganizeId == organizeId && r.ClassifyId == input.classifyId &&
                r.MechanismId == mechanismId && r.Title == input.title && r.Id!=input.id && r.DeleteMark == null);
                if(records!=null) throw YNTKException.Oh(ErrorCode.Workflow0015);
                #endregion

                //entity = input.Adapt<SimpleWorkflowEntity>();
                entity = input.Mapper(entity);
                entity.SharedScope = input.sharedScope.GetHashCode();
                //状态(0.未提交 1.待审核 2.审核不通过 3.已驳回 4.审核通过 5.待确认 6.已完成)
                entity.State = AuditStateEnum.Uncommitted.GetHashCode();//状态改为“未提交”
                entity.Index = 0;//当前节点顺序,修改后重新提交

                #region 保存日常工作记录
                #region 保存日常工作到sqlserver
                entity.LastModifyTime = DateTime.Now;
                entity.LastModifyUserId = userId;
                var isOK = await _recordsRepository.Context.Updateable(entity)
                .IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
                if (!(isOK > 0)) throw YNTKException.Oh(ErrorCode.Workflow0026);
                #endregion

                #region 保存日常工作到mongodb
                var update = await _recordsMongoDbRepository.UpdateAsync(entity, _records, m => m.Id == entity.Id);
                if (!(update.ModifiedCount > 0)) throw YNTKException.Oh(ErrorCode.Workflow0027);
                #endregion
                //保存日常工作相关附件
                await SaveWorkflowFileAsync(entity, input.fileData);
                //保存日常工作动态字段
                await SaveWorkflowDynamicFieldsAsync(entity, input.dynamicData);
                #endregion
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"修改日常工作记录信息发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除日常工作记录
        /// </summary>
        /// <param name="id">日常工作记录id</param>
        /// <returns></returns>
        [HttpDelete("workflow/delete/{id}")]
        public async Task Delete([Required] string id)
        {
            try
            {
                #region 权限验证
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                string roleId = user.Subject.FindFirst(ClaimConst.ROLEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);

                var entity = await GetWorkflowEntityInfoAsync(r => r.Id ==id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Workflow0025);
                if (entity.CreatorUserId != userId) throw YNTKException.Oh(ErrorCode.D1016);
                if (entity.State != AuditStateEnum.Uncommitted.GetHashCode() &&
                    entity.State != AuditStateEnum.NoPass.GetHashCode() &&
                    !(entity.State == AuditStateEnum.Rejected.GetHashCode() && entity.NextDisposenUserId == userId))
                    throw YNTKException.Oh(ErrorCode.Workflow0028);
                #endregion

                #region 删除日常工作记录
                //从sqlserver中删除
                var isOk = await _recordsRepository.Context.Deleteable(entity).ExecuteCommandAsync();
                if (!(isOk > 0))
                    throw YNTKException.Oh(ErrorCode.Workflow0029);
                //从mongodb中删除
                var delete = await _recordsMongoDbRepository.DeleteAsync(_records, m => m.Id == id);
                if (!(delete > 0)) throw YNTKException.Oh(ErrorCode.Workflow0030);
                //删除日常工作相关附件
                await DeleteWorkflowFileAsync(id);
                //删除日常工作记录动态字段数据
                await DeleteWorkflowDynamicFieldsAsync(id);
                //删除日常工作记录流程节点配置数据
                await DeleteWorkflowConfigAsync(id);
                #endregion
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"删除日常工作记录发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 更新日常工作记录状态(启用/禁用)
        /// </summary>
        /// <param name="id">日常工作记录id</param>
        /// <returns></returns>
        [HttpPut("workflow/state/{id}")]
        public async Task UpdateState([Required] string id)
        {
            try
            {
                #region 权限验证
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                string roleId = user.Subject.FindFirst(ClaimConst.ROLEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);

                var entity = await GetWorkflowEntityInfoAsync(r => r.Id == id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Workflow0025);
                if (entity.CreatorUserId != userId) throw YNTKException.Oh(ErrorCode.D1016);
                if (entity.State != AuditStateEnum.Uncommitted.GetHashCode() &&
                    entity.State != AuditStateEnum.NoPass.GetHashCode() &&
                    !(entity.State == AuditStateEnum.Rejected.GetHashCode() && entity.NextDisposenUserId == userId))
                    throw YNTKException.Oh(ErrorCode.Workflow0028);
                #endregion

                var isOk = await _recordsRepository.Context.Updateable<SimpleWorkflowEntity>()
                .SetColumns(it => new SimpleWorkflowEntity()
                {
                    EnabledMark = SqlFunc.IIF(it.EnabledMark == 1, 0, 1),
                    LastModifyUserId = userId,
                    LastModifyTime = SqlFunc.GetDate()
                }).Where(it => it.Id == id).ExecuteCommandAsync();
                if (!(isOk> 0)) throw YNTKException.Oh(ErrorCode.Workflow0031);

                entity.EnabledMark = entity.EnabledMark == 1 ? 0 : 1;
                entity.LastModifyTime = DateTime.Now;
                entity.LastModifyUserId = userId;
                var update = await _recordsMongoDbRepository.UpdateAsync(entity, _records, m => m.Id == entity.Id);
                if (!(update.ModifiedCount > 0)) throw YNTKException.Oh(ErrorCode.Workflow0032);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"更新日常工作记录状态(启用/禁用)发生异常：{ex.Message}");
            }
        }

        #region 提交、审核、确认
        /// <summary>
        /// 获取日常工作当前处理节点信息(下一节点处理人非当前登录用户接口无效)
        /// </summary>
        /// <param name="id">日常工作记录id</param>
        /// <returns></returns>
        [HttpGet("workflow/get/currentnode/{id}")]
        public async Task<TkResult<CurrentDisposenNodeDto>> GetCurrentNodeAsync([Required] string id)
        {
            try
            {
                #region 权限验证
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);

                var entity = await GetWorkflowEntityInfoAsync(r => r.Id == id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Workflow0025);
                if (entity.CreatorUserId != userId && !entity.DisposeUserIds.Contains(userId) && 
                    string.IsNullOrWhiteSpace(entity.NextDisposenNodeId))
                    throw YNTKException.Oh(ErrorCode.D1016);
                if(entity.NextDisposenUserId!= userId) throw YNTKException.Oh(ErrorCode.Workflow0034);
                if (entity.State == AuditStateEnum.Completed.GetHashCode())
                    throw YNTKException.Oh(ErrorCode.Workflow0033);
                #endregion

                return await GetCurrentDisposenNodeAsync(entity.NextDisposenNodeId);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"获取日常工作当前处理节点信息发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 获取日常工作下一处理节点和处理人(当前用户为下一节点处理人并进行处理提交下一节点处理时获取判断用)
        /// </summary>
        /// <param name="id">日常工作记录id</param>
        /// <returns></returns>
        [HttpGet("workflow/get/nextnode/{id}")]
        public async Task<TkResult<NextDisposenNodeDto>> GetNextNodeAsync([Required] string id)
        {
            try
            {
                #region 权限验证
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);

                var entity = await GetWorkflowEntityInfoAsync(r => r.Id == id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Workflow0025);
                if (entity.CreatorUserId != userId && !entity.DisposeUserIds.Contains(userId) &&
                    string.IsNullOrWhiteSpace(entity.NextDisposenNodeId))
                    throw YNTKException.Oh(ErrorCode.D1016);
                if (entity.State== AuditStateEnum.Completed.GetHashCode()) 
                    throw YNTKException.Oh(ErrorCode.Workflow0033);
                #endregion

                return await GetNextNodeAsync(entity.Id,entity.CreatorUserId,entity.Index??0+1);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"获取日常工作下一处理节点和处理人发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 提交、审核、确认日常工作
        /// </summary>
        /// <param name="audit">提交/审核/确认日常工作申请请求模型</param>
        /// <returns></returns>
        [HttpPut("workflow/audit")]
        public async Task AuditAsync([FromBody] SubmitDailyWorkRequestModel audit)
        {
            try
            {
                #region 权限验证
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                string roleId = user.Subject.FindFirst(ClaimConst.ROLEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;
                if (authenticationType == "4" || authenticationType == "5")
                    throw YNTKException.Oh(ErrorCode.D1016);

                var entity = await GetWorkflowEntityInfoAsync(r => r.Id == audit.id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Workflow0025);
                if (entity.CreatorUserId != userId && !entity.DisposeUserIds.Contains(userId) &&
                    string.IsNullOrWhiteSpace(entity.NextDisposenNodeId))
                    throw YNTKException.Oh(ErrorCode.D1016);
                if (entity.State == AuditStateEnum.Completed.GetHashCode())
                    throw YNTKException.Oh(ErrorCode.Workflow0033);

                //获取当前处理节点
                var currentNode = (await GetCurrentDisposenNodeAsync(entity.NextDisposenNodeId)).data;
                //if(currentNode!=null && currentNode.signature && string.IsNullOrWhiteSpace(audit.signatureBase64))
                //    throw YNTKException.Oh(ErrorCode.Workflow0041);
                if(currentNode != null && currentNode.confirm && userId!=entity.CreatorUserId)
                    throw YNTKException.Oh(ErrorCode.Workflow0043);
                //获取下一处理节点
                var nextNode = (await GetNextNodeAsync(entity.Id, entity.CreatorUserId, entity.Index ?? 0 + 1,false)).data;
                if(nextNode!=null && audit.state!= AuditStateTypeEnum.Rejected && 
                    audit.state != AuditStateTypeEnum.NoPass && 
                    string.IsNullOrWhiteSpace(audit.userId)) 
                    throw YNTKException.Oh(ErrorCode.Workflow0042);
                if ((audit.operateType== AuditOperateTypeEnum.Audit && entity.NextDisposenUserId != userId) || 
                    (audit.operateType != AuditOperateTypeEnum.Audit && entity.CreatorUserId != userId)) 
                    throw YNTKException.Oh(ErrorCode.Workflow0034);
                #endregion

                string nodeId = entity.NextDisposenNodeId;//当前处理节点id
                bool sendMessage = false;string toUserId = ""; string title = ""; string bodyText = "";
                switch (audit.operateType)
                {
                    case AuditOperateTypeEnum.SubmitApplications:
                        #region 发起人提交申请
                        if(currentNode!=null) throw YNTKException.Oh(ErrorCode.Workflow0039);
                        if (nextNode == null) throw YNTKException.Oh(ErrorCode.Workflow0024);
                        //状态(0.未提交 1.待审核 2.审核不通过 3.已驳回 4.审核通过 5.待确认 6.已完成)
                        entity.State = AuditStateEnum.Audit.GetHashCode();//待审核
                        entity.NextDisposenNodeId = nextNode.id;//下一处理节点id
                        entity.NextDisposenUserId = audit.userId;//下一节点处理人
                        entity.CurrentDisposenNodeId = "";//当前处理节点id
                        entity.CurrentDisposenUserId = userId;//当前节点处理人
                        entity.Index =1;//当前节点顺序
                        //推送消息
                        sendMessage = true; toUserId = audit.userId;
                        title = $"工作审批【{entity.Title}】待处理";
                        bodyText = $"您有一条待处理的工作审批，标题为“{entity.Title}”，请及时前往处理！";
                        #endregion
                        break;
                    case AuditOperateTypeEnum.Audit:
                        #region 审核
                        if(currentNode==null) throw YNTKException.Oh(ErrorCode.Workflow0040);
                        if (audit.state == AuditStateTypeEnum.Approved)
                        {
                            #region 当前节点审核通过
                            entity.State = nextNode==null ? AuditStateEnum.Completed.GetHashCode() : 
                                (nextNode.confirm ? AuditStateEnum.Confirmed.GetHashCode() : 
                                AuditStateEnum.Audit.GetHashCode());
                           
                            entity.CurrentDisposenNodeId = entity.NextDisposenNodeId;//当前处理节点id
                            entity.CurrentDisposenUserId = userId;//当前节点处理人
                            if (nextNode!=null)
                            {
                                entity.Index = (int?)nextNode.sortCode;//当前节点顺序
                                entity.NextDisposenNodeId = nextNode.id;//下一处理节点id
                                entity.NextDisposenUserId = audit.userId;//下一节点处理人
                                //推送消息
                                sendMessage = true;toUserId = audit.userId;
                                title = $"工作审批【{entity.Title}】待处理";
                                bodyText = $"您有一条待处理的工作审批，标题为“{entity.Title}”，请及时前往处理！";
                            }
                            else
                            {
                                //当前已经是最后一个节点了
                                entity.CurrentDisposenNodeId = "";//当前处理节点id
                                entity.NextDisposenNodeId = "";//下一处理节点id
                                entity.NextDisposenUserId = "";//下一节点处理人
                                entity.Index = 0;//流程已经结束
                                //推送消息
                                sendMessage = true; toUserId = entity.CreatorUserId;
                                title = $"您发起的工作审批【{entity.Title}】已完成";
                                bodyText = $"您于{entity.CreatorTime}发起的工作审批标题为“{entity.Title}”已完成！";
                            }
                            #endregion
                        }
                        else if (audit.state == AuditStateTypeEnum.NoPass)
                        {
                            #region 审核不通过
                            entity.State = AuditStateEnum.NoPass.GetHashCode();
                            entity.Index = 0;//回到发起人,发起人重新修改后提交
                            entity.CurrentDisposenNodeId = "";//当前处理节点id
                            entity.CurrentDisposenUserId = userId;//当前节点处理人
                            entity.NextDisposenNodeId = "";//下一处理节点id
                            entity.NextDisposenUserId = entity.CreatorUserId;//下一节点处理人
                            //推送消息
                            sendMessage = true; toUserId = entity.CreatorUserId;
                            title = $"工作审批【{entity.Title}】审核不通过";
                            bodyText = $"您发起的工作审批标题为“{entity.Title}”审核不通过，请及时前往查看！";
                            #endregion
                        }
                        else if (audit.state == AuditStateTypeEnum.Rejected)
                        {
                            #region 驳回至上一节点
                            entity.State = AuditStateEnum.Rejected.GetHashCode();
                            entity.CurrentDisposenNodeId = entity.NextDisposenNodeId;//当前处理节点id                           
                            var previousNode = await GetPreviousNodeAsync(entity.Id, entity.CreatorUserId, entity.Index ?? 0 + 1);
                            if (previousNode == null)
                            {
                                //驳回到发起人                        
                                entity.NextDisposenNodeId = "";//下一处理节点id
                                entity.NextDisposenUserId = entity.CreatorUserId;//下一节点处理人
                                entity.Index = 0;//驳回到发起人
                                //推送消息
                                sendMessage = true; toUserId = entity.CreatorUserId;
                                title = $"工作审批【{entity.Title}】已驳回";
                                bodyText = $"您于{entity.CreatorTime}发起的工作审批标题为“{entity.Title}”已驳回，请及时前往查看！";
                            }
                            else
                            {
                                //驳回至上一处理节点
                                entity.NextDisposenNodeId = previousNode.Id;//下一处理节点id
                                entity.NextDisposenUserId = entity.CurrentDisposenUserId;//下一节点处理人
                                entity.Index = (int?)previousNode.SortCode;//驳回到发起人
                                //推送消息
                                sendMessage = true; toUserId = entity.CurrentDisposenUserId;
                                title = $"工作审批【{entity.Title}】已驳回";
                                bodyText = $"您处理的工作审批标题为“{entity.Title}”已驳回，请及时前往查看！";
                            }
                            entity.CurrentDisposenUserId = userId;//当前节点处理人
                            #endregion
                        }
                        else throw YNTKException.Oh(ErrorCode.COM1009);
                        #endregion
                        break;
                    case AuditOperateTypeEnum.Confirmed:
                        #region 发起人确认    
                        entity.State = nextNode == null ? AuditStateEnum.Completed.GetHashCode() :
                                (nextNode.confirm ? AuditStateEnum.Confirmed.GetHashCode() :
                                AuditStateEnum.Audit.GetHashCode());

                        entity.CurrentDisposenNodeId = entity.NextDisposenNodeId;//当前处理节点id
                        entity.CurrentDisposenUserId = userId;//当前节点处理人
                        if (nextNode != null)
                        {
                            entity.Index = (int?)nextNode.sortCode;//当前节点顺序
                            entity.NextDisposenNodeId = nextNode.id;//下一处理节点id
                            entity.NextDisposenUserId = audit.userId;//下一节点处理人
                            //推送消息
                            sendMessage = true; toUserId = audit.userId;
                            title = $"工作审批【{entity.Title}】待处理";
                            bodyText = $"您有一条待处理的工作审批，标题为“{entity.Title}”，请及时前往处理！";
                        }
                        else
                        {
                            //当前已经是最后一个节点了
                            entity.CurrentDisposenNodeId = "";//当前处理节点id
                            entity.NextDisposenNodeId = "";//下一处理节点id
                            entity.NextDisposenUserId = "";//下一节点处理人
                            entity.Index = 0;//流程已经结束
                            //推送消息
                            sendMessage = true; toUserId = entity.CreatorUserId;
                            title = $"您发起的工作审批【{entity.Title}】已完成";
                            bodyText = $"您于{entity.CreatorTime}发起的工作审批标题为“{entity.Title}”已完成！";
                        }
                        #endregion
                        break;
                }               

                //添加日常工作审核记录
                await AddWorkflowAuditRecordAsync(entity.Id, nodeId, userId,audit, currentNode?.signature??false);

                #region 修改日常工作记录信息
                if (string.IsNullOrWhiteSpace(entity.DisposeUserIds))
                {
                    entity.DisposeUserIds =string.IsNullOrWhiteSpace(audit.userId) ? 
                        $"{userId}" : $"{userId},{audit.userId}";
                }
                else
                {
                    if (!entity.DisposeUserIds.Contains(userId))
                        entity.DisposeUserIds = $"{entity.DisposeUserIds},{userId}";
                    if (!string.IsNullOrWhiteSpace(audit.userId) && !entity.DisposeUserIds.Contains(audit.userId))
                        entity.DisposeUserIds = $"{entity.DisposeUserIds},{audit.userId}";
                }
                entity.LastModifyTime = DateTime.Now;
                entity.LastModifyUserId = userId;
                var isOK = await _recordsRepository.Context.Updateable(entity)
                .IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
                if (!(isOK > 0)) throw YNTKException.Oh(ErrorCode.Workflow0026);

                var update = await _recordsMongoDbRepository.UpdateAsync(entity, _records, m => m.Id == entity.Id);
                if (!(update.ModifiedCount > 0)) throw YNTKException.Oh(ErrorCode.Workflow0027);
                #endregion

                #region 推送通知公告
                if(sendMessage && !string.IsNullOrWhiteSpace(toUserId)) 
                    await _messageService.SentMessage(new List<string>() {toUserId }, title, bodyText);
                #endregion
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"{audit.operateType.GetDescription()}日常工作发生异常：{ex.Message}");
            }
        }
        #endregion

        /// <summary>
        /// 获取日常工作节点配置数据
        /// </summary>
        /// <param name="id">日常工作记录id</param>
        /// <returns></returns>
        [HttpGet("workflow/getnodes/{id}")]
        public async Task<TkResult<List<WorkflowNodelListDto>>> GetNodeList([Required] string id)
        {
            try
            {
                var nodeList = await GetWorkflowConfigListAsync(r=>r.WorkflowId==id);
                var result = nodeList.Adapt<List<WorkflowNodelListDto>>();
                if (result.Any())
                {
                    #region 处理流程节点返回数据
                    var mechanismIds = result.Where(r => !string.IsNullOrWhiteSpace(r.mechanismId))
                       ?.Select(r => r.mechanismId.Split(',').ToList())
                       ?.SelectMany(r => r).Distinct().ToList();
                    var mechanisms = !mechanismIds.Any() ? new List<MechanismEntity>() :
                        await _mechanismService.GetMechanismListAsync(null, mechanismIds);
                    var roleIds = result.Where(r => !string.IsNullOrWhiteSpace(r.roleId))
                        ?.Select(r => r.roleId).Distinct().ToList();
                    var roles = !roleIds.Any() ? new List<TkRoleEntity>() :
                        await _tkRoleService.GetTkRoleListByIdsAsync(roleIds);
                    var userIds = result.Where(r => !string.IsNullOrWhiteSpace(r.userIds))
                        ?.Select(r => r.userIds.Split(',').ToList())?.ToList()
                        ?.SelectMany(r => r).Distinct().ToList();
                    var users = await _tkUsersService.GetUserListByIds(userIds);
                    result.ForEach(config =>
                    {
                        if (!string.IsNullOrWhiteSpace(config.mechanismId))
                        {
                            config.mechanismName = string.Join('/', mechanisms
                                ?.Where(r => config.mechanismId.Split(',').ToList().Contains(r.Id))
                                ?.Select(r => r.Name).ToList());
                            config.mechanismName = mechanisms?.FirstOrDefault(r => r.Id == config.mechanismId)?.Name;
                        }
                        if (!string.IsNullOrWhiteSpace(config.roleId))
                            config.roleName = roles?.FirstOrDefault(r => r.Id == config.roleId)?.Name;
                        if (!string.IsNullOrWhiteSpace(config.userIds))
                            config.userNames = string.Join(",", users?.Where(r => config.userIds.Split(',').ToList().Contains(r.Id))
                            ?.Select(r => r.RealName)?.ToList());
                    });
                    #endregion
                }
                return TkResult<List<WorkflowNodelListDto>>.Success(result);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"获取日常工作节点配置数据发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 获取日常工作审核记录数据
        /// </summary>
        /// <param name="id">日常工作记录id</param>
        /// <returns></returns>
        [HttpGet("workflow/records/{id}")]
        public async Task<TkResult<List<WorkflowAuditRecordListDto>>> GetAuditRecordList([Required] string id)
        {
            try
            {
                var records = await GetWorkflowAuditRecordListAsync(id);
                var result = records.Adapt<List<WorkflowAuditRecordListDto>>();
                if (result.Any())
                {
                    #region 处理返回数据
                    var operatorIds = result.Select(r => r.operatorId).Distinct().ToList();
                    var operators = await _tkUsersService.GetUserListByIds(operatorIds);
                    result.ForEach(item =>
                    {
                        item.operateTypeText = EnumHelper.GetEnumDescriptionString
                        (item.operateType, typeof(AuditOperateTypeEnum));
                        item.stateText = EnumHelper.GetEnumDescriptionString
                        (item.state, typeof(AuditStateTypeEnum));
                        item.operatorName = operators?.FirstOrDefault(r => r.Id == item.operatorId)?.RealName;
                    });
                    #endregion
                }
                return TkResult<List<WorkflowAuditRecordListDto>>.Success(result);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"获取日常工作审核记录数据发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 获取日常工作审核记录详细信息
        /// </summary>
        /// <param name="id">审核记录唯一标识id</param>
        /// <returns></returns>
        [HttpGet("workflow/recordinfo/{id}")]
        public async Task<TkResult<WorkflowAuditRecordInfoDto>> GetAuditRecord([Required] string id)
        {
            try
            {
                var entity = await GetWorkflowAuditRecordInfoAsync(id);
                var result = entity.Adapt<WorkflowAuditRecordInfoDto>();
                if (result != null)
                {
                    #region 处理返回信息
                    result.operateTypeText = EnumHelper.GetEnumDescriptionString
                        (result.operateType, typeof(AuditOperateTypeEnum));
                    result.stateText = EnumHelper.GetEnumDescriptionString
                    (result.state, typeof(AuditStateTypeEnum));
                    result.operatorName = (await _tkUsersService.GetUserListByIds
                        (new List<string>() { result.operatorId }))?[0].RealName;

                    var files = await GetWorkflowAuditRecordFilesAsync(id);
                    result.fileData= files.Adapt<List<WorkflowFileListDto>>();
                    #endregion
                }
                return TkResult<WorkflowAuditRecordInfoDto>.Success(result);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"获取日常工作审核记录详细信息发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 【工作台专用】获取当前登录用户发起的最新的几条日常工作记录数据
        /// </summary>
        /// <param name="count">条数</param>
        /// <returns></returns>
        [HttpGet("workbench/latest/{count}")]
        public async Task<TkResult<List<DailyWorkListDto>>> GetLatestWorkRecord(int count=7)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                var recordList = new List<DailyWorkListDto>();
                Expression<Func<SimpleWorkflowEntity, bool>> where = m =>
                m.DeleteMark == null && m.CreatorUserId == userId;
                //从mongodb中获取日常工作记录数据
                //排序生成器
                var builderSort = Builders<SimpleWorkflowEntity>.Sort;
                //排序约束   Ascending 正序    Descending 倒序
                var sort = builderSort.Descending(r => r.LastModifyTime);
                //Item1.结果集 Item2.总条数 Item3.总页数
                (List<SimpleWorkflowEntity>, int, int) result =
                    await _recordsMongoDbRepository.GetListAsync(_records,
                    where, 1, count, null, sort);
                recordList = result.Item1.Adapt<List<DailyWorkListDto>>();
                if (!recordList.Any())
                {
                    #region 从sqlserver数据库中获取档案数据
                    var sqlResult = await _recordsRepository.Entities.Where(where)
                         .OrderBy(r => r.LastModifyTime, OrderByType.Desc)
                         .ToPagedListAsync(1, count);
                    recordList = sqlResult.list.Adapt<List<DailyWorkListDto>>();
                    #endregion
                }
                return TkResult<List<DailyWorkListDto>>.Success(recordList);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"【工作台专用】获取当前登录用户发起的最新的{count}条日常工作记录数据发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 【工作台专用】获取当前登录用户最新的几条待处理日常工作记录数据
        /// </summary>
        /// <param name="count">条数</param>
        /// <returns></returns>
        [HttpGet("workbench/beprocessed/{count}")]
        public async Task<TkResult<List<DailyWorkListDto>>> GetBeProcessedWorkRecord(int count = 7)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                var recordList = new List<DailyWorkListDto>();
                Expression<Func<SimpleWorkflowEntity, bool>> where = m =>
                m.DeleteMark == null && m.NextDisposenUserId== userId && m.State!=6;
                //从mongodb中获取日常工作记录数据
                //排序生成器
                var builderSort = Builders<SimpleWorkflowEntity>.Sort;
                //排序约束   Ascending 正序    Descending 倒序
                var sort = builderSort.Descending(r => r.LastModifyTime);
                //Item1.结果集 Item2.总条数 Item3.总页数
                (List<SimpleWorkflowEntity>, int, int) result =
                    await _recordsMongoDbRepository.GetListAsync(_records,
                    where, 1, count, null, sort);
                recordList = result.Item1.Adapt<List<DailyWorkListDto>>();
                if (!recordList.Any())
                {
                    #region 从sqlserver数据库中获取档案数据
                    var sqlResult = await _recordsRepository.Entities.Where(where)
                         .OrderBy(r => r.LastModifyTime, OrderByType.Desc)
                         .ToPagedListAsync(1, count);
                    recordList = sqlResult.list.Adapt<List<DailyWorkListDto>>();
                    #endregion
                }
                return TkResult<List<DailyWorkListDto>>.Success(recordList);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"【工作台专用】获取当前登录用户最新的{count}条待处理日常工作记录数据发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 根据条件获取日常工作记录
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        private async Task<SimpleWorkflowEntity> GetWorkflowEntityInfoAsync(
            Expression<Func<SimpleWorkflowEntity, bool>> where)
        {
            //从从mongodb中获取
            var entity = await _recordsMongoDbRepository.GetAsync(_records, where);
            //再从sqlserver中获取
            if (entity == null) entity = await _recordsRepository.FirstOrDefaultAsync(where);
            return entity;
        }
        #endregion

        #region 日常工作相关附件
        /// <summary>
        /// 获取日常工作相关附件数据
        /// </summary>
        /// <param name="workflowId">日常工作id</param>
        /// <returns></returns>
        private async Task<List<SimpleWorkflowFilesEntity>> GetWorkflowFileListAsync(string workflowId)
        {
            //从mongodb中获取附件数据
            var result = await _filesMongoDbRepository.GetListAsync(_files, r => r.WorkflowId == workflowId);
            if (!result.Any())
            {
                //从sqlserver数据库中获取附件数据
                result = await _filesRepository.Entities
                    .Where(r => r.WorkflowId == workflowId).ToListAsync();
            }
            return result;
        }

        /// <summary>
        /// 保存日常工作相关附件
        /// </summary>
        /// <param name="entity">日常工作信息</param>
        /// <param name="fileData">附件数据</param>
        /// <returns></returns>
        private async Task SaveWorkflowFileAsync(SimpleWorkflowEntity entity,
            List<WorkflowFileRequestModel> fileData)
        {
            try
            {
                _filesRepository.Ado.BeginTran();
                //删除原数据
                await _filesMongoDbRepository.DeleteAsync(_files, r => r.WorkflowId == entity.Id);
                await _filesRepository.DeleteAsync(r => r.WorkflowId == entity.Id);
                if (fileData != null && fileData.Count > 0)
                {
                    var files = new List<SimpleWorkflowFilesEntity>();
                    var file = new SimpleWorkflowFilesEntity();
                    fileData.ForEach(item =>
                    {
                        file = item.Adapt<SimpleWorkflowFilesEntity>();
                        file.Id = YitIdHelper.NextId().ToString();
                        file.OrganizeId = entity.OrganizeId;
                        file.MechanismId = entity.MechanismId;
                        file.WorkflowId = entity.Id;
                        file.CreatorUserId = entity.CreatorUserId;
                        file.CreatorTime = entity.CreatorTime;
                        files.Add(file);
                    });
                    //保存到sqlserver                 
                    var isOk = await _filesRepository.Context.Insertable(files).ExecuteCommandAsync();
                    if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.Workflow0018);
                    //保存到mongodb
                    var succeed = await _filesMongoDbRepository.AddListAsync(files, _files);
                    if (!succeed) throw YNTKException.Oh(ErrorCode.Workflow0019);
                }
                _filesRepository.Ado.CommitTran();
            }
            catch (Exception ex)
            {
                _filesRepository.Ado.RollbackTran();
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"保存日常工作相关附件发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除日常工作相关附件数据
        /// </summary>
        /// <param name="workflowId">日常工作id</param>
        /// <returns></returns>
        private async Task DeleteWorkflowFileAsync(string workflowId)
        {
            var result =await GetWorkflowFileListAsync(workflowId);
            if (result.Any())
            {
                //删除原数据
                await _filesMongoDbRepository.DeleteAsync(_files, r => r.WorkflowId == workflowId);
                await _filesRepository.DeleteAsync(r => r.WorkflowId == workflowId);
                //删除文件
                var deleteFiles = result.Adapt<List<FileListDto>>();
                _fileService.DeleteFiles(deleteFiles);
            }
        }
        #endregion

        #region 日常工作动态字段
        /// <summary>
        /// 获取日常工作动态字段数据
        /// </summary>
        /// <param name="workflowId">日常工作id</param>
        /// <returns></returns>
        private async Task<List<SimpleWorkflowDynamicFieldsEntity>> GetWorkflowDynamicFieldsListAsync(string workflowId)
        {
            //从mongodb中获取动态字段数据
            var result = await _dynamicfieldsMongoDbRepository.GetListAsync(_dynamicfields, r => r.WorkflowId == workflowId);
            if (!result.Any())
            {
                //从sqlserver数据库中获取动态字段数据
                result = await _dynamicfieldsRepository.Entities
                    .Where(r => r.WorkflowId == workflowId).ToListAsync();
            }
            return result;
        }

        /// <summary>
        /// 保存日常工作动态字段
        /// </summary>
        /// <param name="entity">日常工作信息</param>
        /// <param name="fieldData">动态字段数据</param>
        /// <returns></returns>
        private async Task SaveWorkflowDynamicFieldsAsync(SimpleWorkflowEntity entity,
            List<WorkflowDynamicFieldsRequestModel> fieldData)
        {
            try
            {
                _dynamicfieldsRepository.Ado.BeginTran();
                //删除原数据
                await _dynamicfieldsMongoDbRepository.DeleteAsync(_dynamicfields, r => r.WorkflowId == entity.Id);
                await _dynamicfieldsRepository.DeleteAsync(r => r.WorkflowId == entity.Id);
                if (fieldData != null && fieldData.Count > 0)
                {
                    var fields = new List<SimpleWorkflowDynamicFieldsEntity>();
                    var field = new SimpleWorkflowDynamicFieldsEntity();
                    fieldData.ForEach(item =>
                    {
                        field = item.Adapt<SimpleWorkflowDynamicFieldsEntity>();
                        field.Id = YitIdHelper.NextId().ToString();
                        field.OrganizeId = entity.OrganizeId;
                        field.MechanismId = entity.MechanismId;
                        field.WorkflowId = entity.Id;
                        field.CreatorUserId = entity.CreatorUserId;
                        field.CreatorTime = entity.CreatorTime;
                        fields.Add(field);
                    });
                    //保存到sqlserver                 
                    var isOk = await _dynamicfieldsRepository.Context.Insertable(fields).ExecuteCommandAsync();
                    if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.Workflow0020);
                    //保存到mongodb
                    var succeed = await _dynamicfieldsMongoDbRepository.AddListAsync(fields, _dynamicfields);
                    if (!succeed) throw YNTKException.Oh(ErrorCode.Workflow0021);
                }
                _dynamicfieldsRepository.Ado.CommitTran();
            }
            catch (Exception ex)
            {
                _dynamicfieldsRepository.Ado.RollbackTran();
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"保存日常工作动态字段发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除日常工作动态字段数据
        /// </summary>
        /// <param name="workflowId">日常工作id</param>
        /// <returns></returns>
        private async Task DeleteWorkflowDynamicFieldsAsync(string workflowId)
        {
            var result = await GetWorkflowDynamicFieldsListAsync(workflowId);
            if (result.Any())
            {
                //删除原数据
                await _dynamicfieldsMongoDbRepository.DeleteAsync(_dynamicfields, r => r.WorkflowId == workflowId);
                await _dynamicfieldsRepository.DeleteAsync(r => r.WorkflowId == workflowId);
            }
        }
        #endregion

        #region 日常工作流程节点配置
        /// <summary>
        /// 获取日常工作流程节点配置数据
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        private async Task<List<SimpleWorkflowAssociatedConfigEntity>> GetWorkflowConfigListAsync(
            Expression<Func<SimpleWorkflowAssociatedConfigEntity, bool>> where)
        {
            //从mongodb中获取动态字段数据
            var result = await _configurationMongoDbRepository.GetListAsync(_configuration, where);
            if (result == null || result.Count <= 0)
            {
                //从sqlserver数据库中获取动态字段数据
                result = await _configurationRepository.Entities.Where(where).ToListAsync();
            }
            return result;
        }

        /// <summary>
        /// 保存日常工作流程节点配置
        /// </summary>
        /// <param name="entity">日常工作信息</param>
        /// <param name="nodeList">工作流流程节点配置数据</param>
        /// <returns></returns>
        private async Task SaveWorkflowConfigAsync(SimpleWorkflowEntity entity, 
            List<SimpleWorkflowConfigurationEntity> nodeList)
        {
            try
            {
                _configurationRepository.Ado.BeginTran();
                if (nodeList.Any())
                {
                    var nodes = new List<SimpleWorkflowAssociatedConfigEntity>();
                    var node = new SimpleWorkflowAssociatedConfigEntity();
                    nodeList.ForEach(item =>
                    {
                        node = item.Adapt<SimpleWorkflowAssociatedConfigEntity>();
                        node.Id = YitIdHelper.NextId().ToString();
                        node.WorkflowId = entity.Id;
                        nodes.Add(node);
                    });
                    //保存到sqlserver                 
                    var isOk = await _configurationRepository.Context.Insertable(nodes).ExecuteCommandAsync();
                    if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.Workflow0022);
                    //保存到mongodb
                    var succeed = await _configurationMongoDbRepository.AddListAsync(nodes, _configuration);
                    if (!succeed) throw YNTKException.Oh(ErrorCode.Workflow0023);
                }
                _configurationRepository.Ado.CommitTran();
            }
            catch (Exception ex)
            {
                _configurationRepository.Ado.RollbackTran();
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"保存日常工作流程节点配置发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除日常工作流程节点数据
        /// </summary>
        /// <param name="workflowId">日常工作id</param>
        /// <returns></returns>
        private async Task DeleteWorkflowConfigAsync(string workflowId)
        {
            var result = await GetWorkflowConfigListAsync(r=>r.WorkflowId== workflowId);
            if (result.Any())
            {
                await _configurationMongoDbRepository.DeleteAsync(_configuration,m=>m.WorkflowId== workflowId);
                await _configurationRepository.DeleteAsync(r=>r.WorkflowId== workflowId);
            }
        }

        /// <summary>
        /// 获取日常工作当前处理节点信息
        /// </summary>
        /// <param name="currentDisposenNodeId">日常工作当前处理节点id</param>
        /// <returns></returns>
        [NonAction]
        public async Task<TkResult<CurrentDisposenNodeDto>> GetCurrentDisposenNodeAsync(string currentDisposenNodeId)
        {
            if(string.IsNullOrWhiteSpace(currentDisposenNodeId)) 
                return TkResult<CurrentDisposenNodeDto>.Success(null);
            Expression<Func<SimpleWorkflowAssociatedConfigEntity, bool>> where = r =>
            r.Id == currentDisposenNodeId;
            //从mongodb中获取
            var node = await _configurationMongoDbRepository.GetAsync(_configuration, where);
            if (node == null)
            {
                //从sqlserver数据库中获取
                node = await _configurationRepository.FirstOrDefaultAsync(where);
            }
            var result = node.Adapt<CurrentDisposenNodeDto>();
            return TkResult<CurrentDisposenNodeDto>.Success(result);
        }

        /// <summary>
        /// 获取日常工作上一个处理节点信息
        /// </summary>
        /// <param name="workflowId">日常工作id</param>
        /// <param name="creatorUserId">创建人id</param>
        /// <param name="index">当前节点顺序</param>
        /// <returns></returns>
        private async Task<SimpleWorkflowAssociatedConfigEntity> GetPreviousNodeAsync(string workflowId, string creatorUserId, int index)
        {
            Expression<Func<SimpleWorkflowAssociatedConfigEntity, bool>> where = r => 
            r.WorkflowId == workflowId && r.SortCode < index;
            //从mongodb中获取
            var node = await _configurationMongoDbRepository.GetAsync(_configuration, where);
            if (node == null)
            {
                //从sqlserver数据库中获取
                node = await _configurationRepository.FirstOrDefaultAsync(where);
            }
            return node;
        }

        /// <summary>
        /// 获取日常工作下一处理节点信息
        /// </summary>
        /// <param name="workflowId">日常工作id</param>
        /// <param name="creatorUserId">创建人id</param>
        /// <param name="index">当前节点顺序</param>
        /// <param name="conductor">是否需要获取处理人</param>
        /// <returns></returns>
        [NonAction]
        public async Task<TkResult<NextDisposenNodeDto>> GetNextNodeAsync(string workflowId,string creatorUserId, int index,bool conductor=true)
        {
            var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
            string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
            Expression<Func<SimpleWorkflowAssociatedConfigEntity, bool>> where = r =>
            r.WorkflowId == workflowId && r.SortCode > index;
            //从mongodb中获取
            var node = await _configurationMongoDbRepository.GetAsync(_configuration, where);
            if (node==null)
            {
                //从sqlserver数据库中获取
                node = await _configurationRepository.FirstOrDefaultAsync(where);
            }
            var result = node.Adapt<NextDisposenNodeDto>();
            if (result != null && conductor)
            {              
                #region 获取可选处理人
                Expression<Func<UserEntity, bool>> usersWhere = u => 
                u.OrganizeId== organizeId && u.DeleteMark == null && u.EnabledMark == 1;
                if(node.Confirm) usersWhere = usersWhere.And(u => u.Id == creatorUserId);
                else {
                    if (node.UserIds == "System.String[]") node.UserIds = "";
                    if (!string.IsNullOrWhiteSpace(node.UserIds))
                    {
                        var userIds = node.UserIds.Split(',').ToList();
                        usersWhere = usersWhere.And(u => userIds.Contains(u.Id));
                    }
                    else
                    {
                        if (!string.IsNullOrWhiteSpace(node.MechanismId))
                            usersWhere = usersWhere.And(u => u.MechanismId == node.MechanismId);
                        if (!string.IsNullOrWhiteSpace(node.RoleId))
                            usersWhere = usersWhere.And(u => u.RoleId == node.RoleId);
                    }                   
                }
                var users = await _tkUsersService.GetUserListAsync(usersWhere);
                if (users.Any())
                {
                    result.userList = new List<NextNodeDisposenUserListDto>();
                    users.ForEach(user =>
                    {
                        result.userList.Add(new NextNodeDisposenUserListDto()
                        {
                            userId = user.Id,
                            realName = user.RealName,
                            signature=user.Signature
                        });
                    });
                }
                #endregion
            }
            return TkResult<NextDisposenNodeDto>.Success(result);
        }
        #endregion

        #region 日常工作审核记录
        /// <summary>
        /// 添加日常工作审核记录
        /// </summary>
        /// <param name="workflowId">日常工作id</param>
        /// <param name="nodeId">当前审核节点</param>
        /// <param name="userId">当前登录用户</param>
        /// <param name="audit">提交/审核/确认日常工作申请请求模型</param>
        /// <param name="signature">当前节点是否需要签名</param>
        /// <returns></returns>
        private async Task AddWorkflowAuditRecordAsync(string workflowId,string nodeId,string userId,
            SubmitDailyWorkRequestModel audit,bool signature)
        {
            try
            {
                _auditRecordsRepository.Ado.BeginTran();
                _auditRecordFileRepository.Ado.BeginTran();
                var entity = new SimpleWorkflowAuditRecordsEntity();
                entity.Id= YitIdHelper.NextId().ToString();
                entity.WorkflowId = workflowId;//所属工作流id
                entity.NodeId = nodeId;//审核节点id
                entity.OperatorId = userId;//操作人Id
                //操作类型(0.提交申请 1.审核 2.发起人确认)
                entity.OperateType = audit.operateType.GetHashCode();
                //状态(0.提交申请 1.审核通过 2.审核不通过 3.驳回 4.发起人已确认)
                entity.State = audit.state.GetHashCode();
                entity.Description = audit.description;//备注
                entity.CreatorTime = DateTime.Now;//创建时间
               // if (!string.IsNullOrWhiteSpace(audit.signatureBase64))
               if(signature && entity.State!=2 && entity.State!=3)//当前节点需要签名
                {
                    //签名图片存储路径
                    //entity.SignatureImagePath=
                    //    (await _fileService.Base64StringToImage(audit.signatureBase64))?.storagePath;
                    entity.SignatureImagePath = (await _tkUsersService.GetUserInfoByUserId(userId))?.Signature;
                }
                //保存审核记录到sqlsrevre
                var isOk=await _auditRecordsRepository.Context.Insertable(entity).ExecuteCommandAsync();
                if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.Workflow0037);
                //保存审核记录到mongodb
                var succeed = await _auditRecordsMongoDbRepository.AddAsync(entity, _auditRecords);
                if (!succeed) throw YNTKException.Oh(ErrorCode.Workflow0038);

                #region 添加审核附件
                if (audit.fileData!=null && audit.fileData.Count>0)
                {
                    var files = new List<SimpleWorkflowAuditRecordFilesEntity>();
                    var file = new SimpleWorkflowAuditRecordFilesEntity();
                    audit.fileData.ForEach(item =>
                    {
                        file = item.Adapt<SimpleWorkflowAuditRecordFilesEntity>();
                        file.Id = YitIdHelper.NextId().ToString();
                        file.WorkflowId = workflowId;//所属工作流id
                        file.NodeId = nodeId;//审核节点id
                        file.AuditRecordId = entity.Id;//审核记录id
                        file.CreatorTime = entity.CreatorTime;
                        files.Add(file);
                    });
                    //保存到sqlserver                 
                    isOk = await _auditRecordFileRepository.Context.Insertable(files).ExecuteCommandAsync();
                    if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.Workflow0035);
                    //保存到mongodb
                    succeed = await _auditRecordFileMongoDbRepository.AddListAsync(files, _auditRecordFiles);
                    if (!succeed) throw YNTKException.Oh(ErrorCode.Workflow0036);
                }              
                #endregion

                _auditRecordsRepository.Ado.CommitTran();
                _auditRecordFileRepository.Ado.CommitTran();
            }
            catch (Exception ex)
            {
                _auditRecordsRepository.Ado.RollbackTran();
                _auditRecordFileRepository.Ado.RollbackTran();
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"[审核记录]添加日常工作审核记录发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 获取日常工作审核记录相关附件数据
        /// </summary>
        /// <param name="id">审核记录唯一标识id</param>
        /// <returns></returns>
        private async Task<List<SimpleWorkflowAuditRecordFilesEntity>> GetWorkflowAuditRecordFilesAsync(string id)
        {
            //先从mongodb中获取审核记录相关附件数据
            var result = await _auditRecordFileMongoDbRepository.GetListAsync(_auditRecordFiles,m=>m.AuditRecordId==id);
            if (!result.Any())
            {
                //再从sqlserver中获取审核记录相关附件数据
                result = await _auditRecordFileRepository.Entities.Where(r => r.AuditRecordId == id).ToListAsync();
            }
            return result;
        }

        /// <summary>
        /// 获取日常工作审核记录数据
        /// </summary>
        /// <param name="workflowId">日常工作id</param>
        /// <returns></returns>
        private async Task<List<SimpleWorkflowAuditRecordsEntity>> GetWorkflowAuditRecordListAsync(string workflowId)
        {
            //先从mongodb中获取审核记录数据
            var result = await _auditRecordsMongoDbRepository.GetListAsync(_auditRecords,m=>m.WorkflowId==workflowId);
            if(!result.Any())
            {
                //再从sqlserver中获取审核记录数据
                result = await _auditRecordsRepository.Entities.Where(r => r.WorkflowId == workflowId).ToListAsync();
            }
            return result;
        }

        /// <summary>
        /// 获取日常工作审核记录信息
        /// </summary>
        /// <param name="id">审核记录唯一标识id</param>
        /// <returns></returns>
        private async Task<SimpleWorkflowAuditRecordsEntity> GetWorkflowAuditRecordInfoAsync(string id)
        {
            var entity = await _auditRecordsMongoDbRepository.GetAsync(_auditRecords,m=>m.Id==id);
            if (entity == null)
                entity = await _auditRecordsRepository.FirstOrDefaultAsync(r=>r.Id==id);
            return entity;
        }
        #endregion
    }
}
